#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
高级用法示例

该示例展示了配置管理模块的高级用法，包括：
1. 分层配置（全局配置、环境配置、本地配置）
2. 配置加密与安全性
3. 配置验证与类型转换
4. 配置热加载
5. 在实际应用中的使用模式

创建时间：2023-07-01
作者：Python Tools Team
"""

import os
import sys
import time
import threading

# 添加项目根目录到Python路径
sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), '../../../')))

from modules.config.config_manager import ConfigManager, ConfigValidator, get_config_manager
from modules.logger import LogManager


class AppConfig:
    """应用配置类，封装配置管理器，提供应用特定的配置接口"""
    
    def __init__(self, app_name="my_app", env="development"):
        """初始化应用配置
        
        Args:
            app_name: 应用名称
            env: 环境名称（development, testing, production）
        """
        self.app_name = app_name
        self.env = env
        self.logger = LogManager.get_both_logger(name=f"{app_name}_config")
        
        # 获取配置管理器实例
        self.config = get_config_manager(app_name)
        
        # 配置文件路径
        self.config_dir = os.path.dirname(os.path.abspath(__file__))
        self.default_config_path = os.path.join(self.config_dir, 'default_config.json')
        self.env_config_path = os.path.join(self.config_dir, f'{env}_config.json')
        self.local_config_path = os.path.join(self.config_dir, 'local_config.json')
        self.secrets_config_path = os.path.join(self.config_dir, 'secrets.json')
        
        # 初始化配置
        self._init_config()
        
    def _init_config(self):
        """初始化配置，加载各层配置文件"""
        # 创建示例配置文件（仅用于演示）
        self._create_example_config_files()
        
        # 加载默认配置
        self.logger.info(f"加载默认配置: {self.default_config_path}")
        self.config.load_config(self.default_config_path, namespace='default')
        
        # 加载环境配置
        if os.path.exists(self.env_config_path):
            self.logger.info(f"加载环境配置: {self.env_config_path}")
            self.config.load_config(self.env_config_path, namespace='env')
        
        # 加载本地配置（优先级最高）
        if os.path.exists(self.local_config_path):
            self.logger.info(f"加载本地配置: {self.local_config_path}")
            self.config.load_config(self.local_config_path, namespace='local', auto_reload=True)
        
        # 加载加密的敏感配置
        if os.path.exists(self.secrets_config_path):
            self.logger.info(f"加载敏感配置: {self.secrets_config_path}")
            # 设置加密器（在实际应用中，密钥应该从安全的地方获取，而不是硬编码）
            secret_key = self._get_secret_key()
            self.config.set_encryptor(secret_key)
            self.config.load_config(self.secrets_config_path, namespace='secrets')
        
        # 注册配置验证器
        self._register_validators()
        
        # 验证配置
        valid, errors = self.config.validate_config()
        if not valid:
            self.logger.warning("配置验证失败:")
            for key, error in errors.items():
                self.logger.warning(f"  {key}: {error}")
    
    def _get_secret_key(self):
        """获取加密密钥（在实际应用中，应该从环境变量或安全存储中获取）"""
        # 这里仅用于演示，实际应用中不应该硬编码密钥
        return "my-secret-key-for-" + self.app_name
    
    def _register_validators(self):
        """注册配置验证器"""
        # 数据库配置验证
        self.config.register_validator('database.host', ConfigValidator(str, required=True))
        self.config.register_validator('database.port', ConfigValidator(
            int, 
            required=True,
            validator=lambda x: 1024 <= x <= 65535,
            description="数据库端口必须在1024-65535之间"
        ))
        self.config.register_validator('database.username', ConfigValidator(str, required=True))
        self.config.register_validator('database.password', ConfigValidator(str, required=True))
        
        # 应用配置验证
        self.config.register_validator('app.debug', ConfigValidator(bool, default=False))
        self.config.register_validator('app.log_level', ConfigValidator(
            str,
            default="INFO",
            validator=lambda x: x in ('DEBUG', 'INFO', 'WARNING', 'ERROR', 'CRITICAL'),
            description="日志级别必须是有效的级别名称"
        ))
        self.config.register_validator('app.max_threads', ConfigValidator(int, default=10))
    
    def _create_example_config_files(self):
        """创建示例配置文件（仅用于演示）"""
        # 默认配置
        default_config = {
            "app": {
                "name": self.app_name,
                "version": "1.0.0",
                "debug": False,
                "log_level": "INFO",
                "max_threads": 10
            },
            "database": {
                "host": "localhost",
                "port": 3306,
                "username": "user",
                "password": "password",  # 在实际应用中，密码应该放在加密的配置文件中
                "database": self.app_name
            },
            "cache": {
                "enabled": True,
                "type": "memory",
                "ttl": 3600
            }
        }
        
        # 环境配置（开发环境）
        dev_config = {
            "app": {
                "debug": True,
                "log_level": "DEBUG"
            },
            "database": {
                "database": f"{self.app_name}_dev"
            }
        }
        
        # 环境配置（测试环境）
        test_config = {
            "app": {
                "debug": False,
                "log_level": "INFO"
            },
            "database": {
                "host": "test-db.example.com",
                "database": f"{self.app_name}_test"
            }
        }
        
        # 环境配置（生产环境）
        prod_config = {
            "app": {
                "debug": False,
                "log_level": "WARNING",
                "max_threads": 50
            },
            "database": {
                "host": "prod-db.example.com",
                "database": self.app_name,
                "pool_size": 20
            },
            "cache": {
                "type": "redis",
                "host": "redis.example.com",
                "port": 6379
            }
        }
        
        # 本地配置（开发者个人配置，优先级最高）
        local_config = {
            "app": {
                "debug": True
            },
            "database": {
                "host": "127.0.0.1",
                "port": 3307
            }
        }
        
        # 敏感配置（加密存储）
        secrets_config = {
            "database": {
                "password": "super-secret-password"
            },
            "api": {
                "key": "api-key-12345",
                "secret": "api-secret-67890"
            }
        }
        
        # 保存配置文件
        import json
        os.makedirs(self.config_dir, exist_ok=True)
        
        with open(self.default_config_path, 'w', encoding='utf-8') as f:
            json.dump(default_config, f, indent=2, ensure_ascii=False)
        
        # 根据当前环境保存对应的环境配置
        env_config = {
            "development": dev_config,
            "testing": test_config,
            "production": prod_config
        }.get(self.env, dev_config)
        
        with open(self.env_config_path, 'w', encoding='utf-8') as f:
            json.dump(env_config, f, indent=2, ensure_ascii=False)
        
        with open(self.local_config_path, 'w', encoding='utf-8') as f:
            json.dump(local_config, f, indent=2, ensure_ascii=False)
        
        # 加密敏感配置前先保存原始文件（仅用于演示）
        with open(self.secrets_config_path, 'w', encoding='utf-8') as f:
            json.dump(secrets_config, f, indent=2, ensure_ascii=False)
    
    def get_database_config(self):
        """获取数据库配置
        
        Returns:
            dict: 数据库配置字典
        """
        # 按优先级从高到低查找配置
        db_config = {}
        
        # 从默认配置获取基础配置
        default_db = self.config.get_dict('default.database', {})
        db_config.update(default_db)
        
        # 从环境配置获取环境特定配置
        env_db = self.config.get_dict('env.database', {})
        db_config.update(env_db)
        
        # 从本地配置获取开发者特定配置
        local_db = self.config.get_dict('local.database', {})
        db_config.update(local_db)
        
        # 从加密配置获取敏感配置
        if 'password' in self.config.get_dict('secrets.database', {}):
            db_config['password'] = self.config.get_encrypted('secrets.database.password')
        
        return db_config
    
    def get_app_config(self):
        """获取应用配置
        
        Returns:
            dict: 应用配置字典
        """
        # 按优先级从高到低查找配置
        app_config = {}
        
        # 从默认配置获取基础配置
        default_app = self.config.get_dict('default.app', {})
        app_config.update(default_app)
        
        # 从环境配置获取环境特定配置
        env_app = self.config.get_dict('env.app', {})
        app_config.update(env_app)
        
        # 从本地配置获取开发者特定配置
        local_app = self.config.get_dict('local.app', {})
        app_config.update(local_app)
        
        return app_config
    
    def get_api_credentials(self):
        """获取API凭证
        
        Returns:
            tuple: (API密钥, API密钥)
        """
        api_key = self.config.get_encrypted('secrets.api.key', '')
        api_secret = self.config.get_encrypted('secrets.api.secret', '')
        return api_key, api_secret


class DatabaseService:
    """数据库服务类，演示如何使用配置"""
    
    def __init__(self, app_config):
        """初始化数据库服务
        
        Args:
            app_config: 应用配置实例
        """
        self.app_config = app_config
        self.logger = LogManager.get_both_logger(name="database_service")
        self.db_config = self.app_config.get_database_config()
        self.logger.info("数据库服务已初始化")
    
    def connect(self):
        """连接到数据库（模拟）"""
        host = self.db_config.get('host')
        port = self.db_config.get('port')
        username = self.db_config.get('username')
        password = self.db_config.get('password')
        database = self.db_config.get('database')
        
        self.logger.info(f"连接到数据库: {username}@{host}:{port}/{database}")
        # 在实际应用中，这里会使用实际的数据库连接代码
        print(f"模拟连接到数据库: {username}@{host}:{port}/{database}")
        
        return True


class ApiService:
    """API服务类，演示如何使用加密配置"""
    
    def __init__(self, app_config):
        """初始化API服务
        
        Args:
            app_config: 应用配置实例
        """
        self.app_config = app_config
        self.logger = LogManager.get_both_logger(name="api_service")
        self.api_key, self.api_secret = self.app_config.get_api_credentials()
        self.logger.info("API服务已初始化")
    
    def make_api_call(self, endpoint, data):
        """调用API（模拟）
        
        Args:
            endpoint: API端点
            data: 请求数据
            
        Returns:
            dict: 响应数据
        """
        self.logger.info(f"调用API: {endpoint}")
        # 在实际应用中，这里会使用实际的API调用代码
        print(f"模拟API调用: {endpoint}")
        print(f"使用API密钥: {self.api_key[:3]}...{self.api_key[-3:]}")
        
        return {"status": "success", "data": data}


class Application:
    """应用类，演示如何在实际应用中使用配置"""
    
    def __init__(self, app_name="my_app", env="development"):
        """初始化应用
        
        Args:
            app_name: 应用名称
            env: 环境名称
        """
        self.app_name = app_name
        self.env = env
        self.logger = LogManager.get_both_logger(name=app_name)
        
        # 初始化配置
        self.config = AppConfig(app_name, env)
        
        # 初始化服务
        self.db_service = DatabaseService(self.config)
        self.api_service = ApiService(self.config)
        
        # 获取应用配置
        self.app_config = self.config.get_app_config()
        
        self.logger.info(f"应用已初始化: {app_name} ({env})")
        self.logger.info(f"应用配置: {self.app_config}")
    
    def run(self):
        """运行应用"""
        self.logger.info(f"启动应用: {self.app_name}")
        
        # 连接数据库
        self.db_service.connect()
        
        # 调用API
        self.api_service.make_api_call("/api/v1/data", {"key": "value"})
        
        # 演示配置热加载
        self._demonstrate_hot_reload()
        
        self.logger.info(f"应用运行完成: {self.app_name}")
    
    def _demonstrate_hot_reload(self):
        """演示配置热加载"""
        print("\n演示配置热加载...")
        print("当前本地配置文件路径:", self.config.local_config_path)
        print("当前数据库端口:", self.config.config.get_int('local.database.port'))
        
        print("\n请在5秒内手动修改本地配置文件中的数据库端口...")
        for i in range(5):
            print(f"等待中... {5-i} 秒")
            time.sleep(1)
        
        # 检查配置是否已更新
        new_port = self.config.config.get_int('local.database.port')
        print(f"更新后的数据库端口: {new_port}")


def main():
    """主函数"""
    # 创建并运行应用
    app = Application(app_name="config_demo", env="development")
    app.run()


if __name__ == "__main__":
    main()